<?php

namespace App\ModelBase;


use App\Common\DB\CommonMysql;
use App\Traits\TraitCommon;
use App\Traits\TraitConnectDB;
use App\X\EHelper;
use Carbon\Carbon;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use XWX\Common\H;
use XWX\Common\XArray\XArray;
use XWX\Common\XEntity;

class AppModel extends XEntity
{
    use TraitConnectDB, TraitCommon;


    static public function prefix()
    {
        return '';
    }


    static public function table()
    {
        return null;
    }


    /**
     * 获取字段名
     *
     * @param $key
     * @return string
     */
    public function funcGetName($key)
    {
        return $this::prefix() . $key;
    }


    public function funcGetX()
    {
        return $this->getVal($this->funcGetName('x_id'));
    }

    public function funcSetX($x)
    {
        $this->setVal($this->funcGetName('x_id'), $x);
    }


    /**
     * ID赋值
     */
    public function funcSetAutoID()
    {
        $this->setVal($this->funcIdKey(), EHelper::funcGetID($this::prefix()));
    }

    /**
     * 主键key
     *
     * @return string
     */
    public function funcIdKey()
    {
        return $this->funcGetName('id');
    }

    public function funcGetID()
    {
        return $this->getVal($this->funcIdKey());
    }


    public function funcToXArray()
    {
        $arr = $this->toArray();

        return XArray::funcIns($arr);
    }


    public function fill(array $data, $do_set_keys = false)
    {
        $_data = [];
        foreach ($data as $k => $v)
        {
            $val = $v;
            if (H::funcStrEndsWith($k, '_date'))
            {
                //date后缀，将为时间对象
                if (is_string($v))
                {
                    $val = Carbon::parse($v);
                }
            }

            $_data[$k] = $val;
        }

        parent::fill($_data, $do_set_keys);
    }


    /**
     * 插入
     *
     * @return bool|int
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    public function funcInsert()
    {
        $arr = $this->toArray($this::FILTER_NOT_NULL);
        $r = $this->db()->insert($this::table(), $arr);
        if ($r == false)
        {
            throw new \Exception($this->db()->getLastError());
        }

        return $r;
    }

    /**
     * 更新
     *
     * @param null $data 更新字段
     * @return mixed
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    public function funcUpdate($data = null)
    {
        if ($data === null)
        {
            $data = $this->toArray();
        }
        else
        {
            //有传更新参数的，视为改变值
            $this->fill($data, true);
        }


        //需要更新的keys
        $update_keys = $this->keysSet();
        $update_data = array_filter($data, function ($v, $k) use ($update_keys)
        {
            if ($this->funcIdKey() == $k
                || $this->funcGetName('x_id') == $k)
            {
                return false;
            }

            if (in_array($k, $update_keys))
            {
                return true;
            }


            return false;
        }, 1);


        $r = false;
        if (count($update_data) > 0)
        {
            $r = $this->db()
                ->where($this->funcIdKey(), $this->getVal($this->funcIdKey()))
                ->update($this::table(), $update_data, 1);
            if ($r == false)
            {
                throw new \Exception($this->db()->getLastError());
            }
        }


        return $r;
    }


    /**
     * @param CommonMysql $db
     * @param $x
     * @param $id
     * @return $this|null
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    static public function funcXLoad(CommonMysql $db, $x, $id)
    {
        $entity = static::funcXGet($db, $x, $id);
        if ($entity === null)
        {
            $table = static::table();
            throw new \Exception("entity is null, table={$table}, id={$id}");
        }

        return $entity;
    }

    /**
     * @param CommonMysql $db
     * @param $x
     * @param $id
     * @return $this|null
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    static public function funcXGet(CommonMysql $db, $x, $id)
    {
        $entity = static::funcGet($db, $id);
        if ($entity === null)
        {
            return null;
        }

        $fd_x = $entity->{static::prefix() . 'x_id'};
        if ($fd_x !== $x)
        {
            $table = static::table();
            throw new \Exception("x error, table={$table}, id={$id}, fd_x={$fd_x}, x={$x}");
        }

        return $entity;
    }


    /**
     * @param CommonMysql $db
     * @param $id
     * @return $this|null
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    static public function funcLoad(CommonMysql $db, $id)
    {
        $entity = static::funcGet($db, $id);
        if ($entity === null)
        {
            $table = static::table();
            throw new \Exception("entity is null, table={$table}, id={$id}");
        }

        return $entity;
    }

    /**
     * @param CommonMysql $db
     * @param $id
     * @return $this|null
     * @throws \EasySwoole\Mysqli\Exceptions\ConnectFail
     * @throws \EasySwoole\Mysqli\Exceptions\PrepareQueryFail
     * @throws \Throwable
     */
    static public function funcGet(CommonMysql $db, $id)
    {
        $arr = $db->where(static::prefix() . 'id', $id)
            ->getOne(static::table());
        if ($arr === null)
        {
            return null;
        }

        $entity = new static($arr);

        return $entity;
    }


    /**
     * 数据转实体
     *
     * @param $class
     * @param $arr
     * @return $this
     */
    static public function funcArrayToEntity($arr)
    {
        if ($arr === null)
        {
            return null;
        }

        if (count($arr) <= 0)
        {
            return null;
        }


        $class = static::class;
        $entity = new $class($arr);

        return $entity;
    }
}